package com.cqq.auth.shiro.realm;

import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cqq.auth.constant.UserStatus;
import com.cqq.auth.service.PermissionService;
import com.cqq.auth.service.RoleService;
import com.cqq.auth.service.UserService;
import com.cqq.auth.service.bean.PermissionBean;
import com.cqq.auth.service.bean.RoleBean;
import com.cqq.auth.service.bean.UserBean;
import com.cqq.common.core.constant.SessionConstant;
import com.cqq.common.core.util.PasswordEncoder;

public class UserRealm extends AuthorizingRealm {

	private static final Logger log = LoggerFactory.getLogger(UserRealm.class);
	
	private String systemCode;
	
	private UserService userService;
	
	private RoleService roleService;
	
	private PermissionService permissionService;
	
	public void setSystemCode(String systemCode) {
		this.systemCode = systemCode;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}

	public void setPermissionService(PermissionService permissionService) {
		this.permissionService = permissionService;
	}

	@Override
	public boolean supports(AuthenticationToken token) {
		// 仅支持UsernamePasswordToken类型的Token
		return token instanceof UsernamePasswordToken;
	}
	
	//授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		log.debug("get roles and permissions ...");
		String username=(String)super.getAvailablePrincipal(principals);
		List<RoleBean> roles=this.roleService.listRoleByUsername(username,systemCode);
		List<PermissionBean> perms=this.permissionService.listPermissionByUsername(username, systemCode);
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		for(RoleBean role:roles){
			info.addRole(role.getCode());
			log.debug("add role: {}",role.getCode());
		}
		for(PermissionBean perm:perms){
			info.addStringPermission(perm.getCode());
			log.debug("add permission: {}",perm.getCode());
		}
		return info;
	}

	//认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authToken;
		String username = token.getUsername();
		String password = String.valueOf(token.getPassword());
		log.debug("get user[{}] auth info ...",username);
		UserBean user=this.userService.findUser(username);
		if(user==null){
			throw new UnknownAccountException();
		}
		if(UserStatus.DISABLED.equals(user.getStatus())){
			throw new DisabledAccountException();
		}
		if(UserStatus.LOCKED.equals(user.getStatus())){
			throw new LockedAccountException();
		}
		if(!UserStatus.ENABLED.equals(user.getStatus())){
			throw new DisabledAccountException();
		}
		if(token.getPassword().length > 0){
			String pwd=PasswordEncoder.encode(password, user.getUsername());
			if(!user.getPassword().equalsIgnoreCase(pwd)){
				throw new IncorrectCredentialsException();
			}
		}
		user.setPassword(null);
		this.setSession(SessionConstant.LOGIN_USER, user);
		AuthenticationInfo info = new SimpleAuthenticationInfo(username, password, super.getName());
		return info;
	}

	public void clearCachedAuthorizationInfo(String principal) {  
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, super.getName());  
        super.clearCachedAuthorizationInfo(principals);  
    }
	
	private void setSession(Object key, Object value) {
		Subject currentUser = SecurityUtils.getSubject();
		if (currentUser!=null) {
			Session session = currentUser.getSession(true);
			if (session!=null) {
				session.setAttribute(key, value);
			}
		}
	}
}